// 声明的变量都是全局变量，因此每个文件中加入一个export {},就会变成js模块，那么文件中的变量成为私有
export {}

// 装饰器需要在tsconfig.json中加入experimentalDecorators": true 来支持装饰器

// 关于类继承
// 第一种情况，super作为函数调用时，代表父类的构造函数。(只能在constructor中存在)
// 第二种情况，super作为对象时，在普通方法中，指向父类的原型对象；在静态方法中，指向父类。


// 1.类的定义
// class Person{
//     name133:string;
//     getName():void{
//         console.log(this.name133);
//     }
// }
// let p1 = new Person();
// p1.name133 = 'ikki';
// p1.getName();

// 2.存取器
// class User {
//     myname:string;
//     constructor(myname: string) {
//         this.myname = myname;
//     }
//     get name() {
//         return this.myname;
//     }
//     set name(value) {
//         this.myname = value;
//     }
// }

// let user = new User('ikki');
// user.name = 'jiagou'; 
// console.log(user.name); 
// 编译后
// "use strict";
// var User = /** @class */ (function () {
//     function User(myname) {
//         this.myname = myname;
//     }
//     Object.defineProperty(User.prototype, "name", {
//         get: function () {
//             return this.myname;
//         },
//         set: function (value) {
//             this.myname = value;
//         },
//         enumerable: true,
//         configurable: true
//     });
//     return User;
// }());
// var user = new User('ikki');
// user.name = 'jiagou';
// console.log(user.name);

// 3.参数属性
// class User {
//     constructor(public myname: string) {}
//     get name() {
//         return this.myname;
//     }
//     set name(value) {
//         this.myname = value;
//     }
// }
// let user = new User('ikki');
// console.log(user.name); 
// user.name = 'jiagou'; 
// console.log(user.name);

// 4.readonly
// readonly修饰的变量只能在构造函数中初始化
// 在 TypeScript 中，const 是常量标志符，其值不能被重新分配
// TypeScript 的类型系统同样也允许将 interface、type、 class 上的属性标识为 readonly
// readonly 实际上只是在编译阶段进行代码检查。而 const 则会在运行时检查（在支持 const 语法的 JavaScript 运行时环境中）
// class Animal {
//     public readonly name: string
//     constructor(name:string) {
//         this.name = name;
//     }
//     changeName(name:string){
//         this.name = name;
//     }
// }
// let a = new Animal('ikki');
// a.changeName('jiagou');

// 5.继承
// class Person {
//     name: string;//定义实例的属性，默认省略public修饰符
//     age: number;
//     constructor(name:string,age:number) {//构造函数
//         this.name=name;
//         this.age=age;
//     }
//     getName():string {
//         return this.name;
//     }
//     setName(name:string): void{
//         this.name=name;
//     }
// }
// class Student extends Person{
//     no: number;
//     constructor(name:string,age:number,no:number) {
//         super(name,age);
//         this.no=no;
//     }
//     getNo():number {
//         return this.no;
//     }
// }
// let s1=new Student('zfpx',10,1);
// console.log(s1);

// 6.类里面的修饰符
// class Father {
//     public name: string;  //类里面 子类 其它任何地方外边都可以访问
//     protected age: number; //类里面 子类 都可以访问,其它任何地方不能访问
//     private money: number; //类里面可以访问， 子类和其它任何地方都不可以访问
//     constructor(name:string,age:number,money:number) {//构造函数
//         this.name=name;
//         this.age=age;
//         this.money=money;
//     }
//     getName():string {
//         return this.name;
//     }
//     setName(name:string): void{
//         this.name=name;
//     }
// }
// class Child extends Father{
//     constructor(name:string,age:number,money:number) {
//         super(name,age,money);
//     }
//     desc() {
//         console.log(`${this.name} ${this.age} ${this.money}`); //报错 属性“money”为私有属性，只能在类“Father”中访问。ts(2341)
//     }
// }
// let child = new Child('zfpx',10,1000);
// console.log(child.name);
// console.log(child.age); //报错
// console.log(child.money); //报错 属性“money”为私有属性，只能在类“Father”中访问。ts(2341)

// 7.静态属性 静态方法
// class Father {
//     static className='Father';
//     static getClassName() {
//         return Father.className;
//     }
//     public name: string;
//     constructor(name:string) {//构造函数
//         this.name=name;
//     }
// }
// console.log(Father.className);
// console.log(Father.getClassName());


// 8.装饰器
// 装饰器是一种特殊类型的声明，它能够被附加到类声明、方法、属性或参数上，可以修改类的行为
// 常见的装饰器有类装饰器、属性装饰器、方法装饰器和参数装饰器
// 装饰器的写法分为普通装饰器和装饰器工厂

// 8.1类装饰器
namespace a {
    function addNameEat(constructor){
        constructor.prototype.name = 'ikki';
        constructor.prototype.eat = function(){}
    }
    @addNameEat
    class Person {
        name:string;
        eat:Function;
        constructor(){}
    }
    let p = new Person()
    console.log(p.name);
    p.eat()
}
// 类的替换
namespace c {
    //还可以替换类,不过替换的类要与原类结构相同
    function enhancer(constructor: Function) {
        return class {
            name: string = "jiagou";
            eat() {
            console.log("吃饭饭");
            }
        };
    }
    @enhancer
    class Person {
      name!: string;
      eat!: Function;
      constructor() {}}
    let p: Person = new Person();
    console.log(p.name);
    p.eat();
}
// 8.2属性装饰器
// 第一个参数对于静态成员来说是类的构造函数，对于实例成员是类的原型对象
// 第二个参数是属性的名称
namespace c {
    function upperCase(target: any, propertyKey: string) {
        let value = target[propertyKey];
        const getter = function () {
            return value;
        }
        // 用来替换的setter
        const setter = function (newVal: string) {
            value = newVal.toUpperCase()
        };
        // 替换属性，先删除原先的属性，再重新定义属性
        if (delete target[propertyKey]) {
            Object.defineProperty(target, propertyKey, {
                get: getter,
                set: setter,
                enumerable: true,
                configurable: true
            });
        }
    }
    class Person {
        @upperCase
        name: string = 'ikki'
        constructor() { }
    }
    let p: Person = new Person();
    console.log(p.name);
    
}
// 8.3方法装饰器
// 第一个参数对于静态成员来说是类的构造函数，对于实例成员是类的原型对象
// 第二个参数是方法的名称
// 第三个参数是方法描述符
namespace d {
    function noEnumerable(target: any, property: string, descriptor: PropertyDescriptor) {
        console.log('target.getName', target.getName);
        console.log('target.getAge', target.getAge);
        descriptor.enumerable = true;
    }
    class Person {
        constructor() { }
        @noEnumerable
        getName() {
            console.log('haha');
        }
    }
    let p: Person = new Person();
    console.log(p.getName());
}
// 8.4参数装饰器 会在运行时当作函数被调用，可以使用参数装饰器为类的原型增加一些元数据
// 第1个参数对于静态成员是类的构造函数，对于实例成员是类的原型对象
// 第2个参数的名称
// 第3个参数在函数列表中的索引
namespace e {
    interface Person {
        age: number;
    }
    function addAge(target: any, methodName: string, paramsIndex: number) {
        console.log(target);
        console.log(methodName);
        console.log(paramsIndex);
        target.age = 10;
    }
    class Person {
        login(username: string, @addAge password: string) {
            console.log(this.age, username, password);
        }
    }
    let p = new Person();
    p.login('ikki', '123456')
}
// 8.5装饰器工厂：就是高阶函数
namespace b {
    function addNameEatFactory(name:string){
        return function addNameEat(target:any){
            target.prototype.name = 'ikki'+name;
            target.prototype.eat = function(){}
        }
    }
    @addNameEatFactory('真棒')
    class Person {
        name:string;
        eat:Function;
        constructor(){}
    }
    let p = new Person()
    console.log(p.name);
    p.eat()
}
// 8.6装饰器执行顺序
// 类装饰器总是最后执行,而且从书写顺序自下向上
// 方法和方法参数中参数装饰器先执行。从最后一个参数依次向前执行
// 方法和属性装饰器，谁在前面谁先执行。因为参数属于方法一部分，所以参数会一直紧紧挨着方法执行

// 9.抽象类 无法被实例化，只能被继承
namespace f {
    abstract class Animal {
        name!:string;
        // 抽象方法不能在抽象类中实现，只能在抽象类的具体子类中实现，而且必须实现
        abstract speak():void;
    }
    class Cat extends Animal {
        speak():void{
            console.log('喵喵');
        }
    }
    class Dog extends Animal {
        speak():void{
            console.log('汪汪');
        }
    }
}

// 10.重写(override) vs 重载(overload)
// 重写是指子类重写继承自父类中的方法
// 重载是指为同一个函数提供多个类型定义(函数的重载)

// 11.继承 vs 多态
// 继承(Inheritance)子类继承父类，子类除了拥有父类的所有特性外，还有一些更具体的特性
// 多态(Polymorphism)同一个方法不同的子类有不同的实现(Dog和Cat的speak方法)